#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <sys/epoll.h> 

using namespace std;

int initserver(uint16_t port);

int main(int argc, char *argv[]) {
    if (argc != 2) { cout << "param error" << endl; return -1; }

    int listensock = initserver(atoi(argv[1]));
    if (listensock < 0) { cout << "listensock() error" << endl; return -1; }

    int epollfd = epoll_create(1);

    epoll_event ev;
    ev.data.fd = listensock;
    ev.events = EPOLLIN;

    epoll_ctl(epollfd, EPOLL_CTL_ADD, listensock, &ev);
    epoll_event evs[10];

    while(1) {
        int infds = epoll_wait(epollfd, evs, 10, -1);
        cout << "epoll_wait()" << endl;

        if (infds < 0) { cout << "epoll error" << endl; break; }
        else if (infds == 0) { cout << "epoll timeout" << endl; continue; } 
        else {
            for (int i = 0; i < infds; i ++) {
                if (evs[i].data.fd == listensock) {
                    struct sockaddr_in client;
                    socklen_t len = sizeof(client);
                    int clientsock = accept(listensock,(struct sockaddr*)&client, &len);
                    if (clientsock < 0) { cout << "accept() failed" << endl; continue; }

                    ev.data.fd = clientsock;
                    ev.events = EPOLLIN;
                    epoll_ctl(epollfd, EPOLL_CTL_ADD, clientsock, &ev);
                } else {
                    char buffer[1024];
                    memset(buffer,0,sizeof(buffer));
                    
                    if ( recv(evs[i].data.fd, buffer, sizeof(buffer), 0) <= 0 ) {
                        cout << "client discount: " << evs[i].data.fd << endl;
                        close(evs[i].data.fd);
                    } else {
                        send(evs[i].data.fd, buffer, strlen(buffer), 0);
                    }
                }
            }
        }
    }

    close(listensock);
    return 0;
}

int initserver(uint16_t port) {
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if (sock < 0) {
        cout << "socket() failed" << endl; return -1;
    }
    int opt = 1; 
    unsigned int len = sizeof(opt);
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR, &opt, len);
    
    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port);

    if (bind(sock, (struct sockaddr *)&servaddr,sizeof(servaddr))) { 
        cerr << "Error binding socket: " << strerror(errno) << endl;
        close(sock); 
        return -1;
    }

    if (listen(sock, 5)) {
        cerr << "Error listening on socket: " << strerror(errno) << endl;
        close(sock);
        return -1;
    }
    return sock;
}